<script lang="ts" setup name="proForm">
defineOptions({
  // name: "pro-form",
});
import dayjs, { Dayjs } from "dayjs";
import { message, Modal } from "ant-design-vue";
import { ref, reactive, computed } from "vue";
import type { Column } from "@/components/ProTable/ProTable.vue";

import { defaultRules } from "./validate";

import { UploadFile } from "@/components/Upload";

import { useGlobalStore } from "@/stores";
const { dictionary, getValByDictionary } = useGlobalStore();
// console.log(dictionary);

const dictionaryKeys = Object.keys(dictionary);

/** 表单item配置项 */
export interface Mapping {
  label: string;
  prop: string;

  type: keyof typeof FormItemMap;

  columns?: Column[]; //表单项为表格时，表格字段与列的映射

  dateFormat?: string;
  isAfterToday?: boolean;

  /** 多选模式（select选择器）*/
  multiple?: boolean;

  options?: Option[];
  required?: boolean;
  rules?: any;

  col?: number;
  width?: string;
}

export interface Option {
  label: string;
  value: any;
}

export interface Props {
  modelValue: any;
  mapping: Mapping[];
  defaultCol?: number;
  readonly?: boolean;
}

// 组件渲染映射表
enum FormItemMap {
  "input" = "a-input",
  "textarea" = "a-textarea",
  "input-number" = "a-input-number",

  "select" = "a-select",
  // "select-multiple" = "a-select",
  "switch" = "a-switch",
  "radio" = "a-radio-group",
  "checkbox" = "a-checkbox-group",

  "date" = "a-date-picker",
  "date-range" = "a-range-picker",

  "upload" = "a-upload",
  "table" = "a-table",
}
enum FormItemOptionMap {
  "select" = "a-select-option",
  "checkbox" = "a-checkbox",
  "radio" = "a-radio",
}

const inputTextType = ["input", "textarea", "input-number"];

const placeholderText = (type: string) =>
  inputTextType.includes(type) ? "输入" : "选择";

const OptionTypes = Object.keys(FormItemOptionMap);

const props = defineProps<Props>();
// console.log(props);

const emit = defineEmits<{ "update:modelValue": any; submit: [] }>();

// 动态修改表单项大小占比
const screenWidth = document.body.clientWidth;
const dynamicCol = (col: number | undefined) => {
  if (!col) return 24; // 表单项span默认值24
  else return (col * (1920 / screenWidth)).toFixed();
};

const likeSearchFn = (input: string, option: any) => {
  return option.label?.indexOf(input) >= 0;
};

const formRef = ref();

const verify = async () => {
  return new Promise<void>((resolve, reject) => {
    formRef.value
      ?.validate()
      .then((formValue: any) => {
        resolve(formValue);
      })
      .catch(({ errorFields }: any) => {
        // reject(errorFields);
      });
  });
};
const reset = async () => {
  await formRef.value?.resetFields();
  emit("submit");
};

defineExpose({ verify, reset });

defineSlots<{
  header?: (props: any) => any;
  footer?: (props: any) => any;
  default?: (props: any) => any;
}>();

// 不可选择的日期
const isAfterToday = (current: Dayjs) => {
  // Can not select days before today and today
  return current && current < dayjs().endOf("day");
};
</script>

<template>
  <a-form
    ref="formRef"
    class="pro-form"
    :model="props.modelValue"
    auto-label-width
  >
    <a-row :gutter="[30, 15]" class="w-full">
      <a-col>
        <slot name="header"></slot>
      </a-col>
      <a-col
        :span="dynamicCol(item.col || props.defaultCol)"
        v-for="(item, index) in props.mapping"
        :key="'pro_form_item_' + index"
      >
        <a-form-item
          :name="item.prop"
          :label="item.label"
          :rules="item.rules || defaultRules(item)"
        >
          <!-- 表单项修改时可触发搜索 -->
          <!--  @change="emit('submit')" -->

          <!-- 表格 -->
          <template v-if="item.type === 'table'">
            <ProTable
              :data="props.modelValue[item.prop]"
              :columns="item.columns"
            />
          </template>

          <template v-else-if="item.type === 'switch'">
            <a-switch
              v-model:checked="props.modelValue[item.prop]"
              :checkedValue="2"
              :unCheckedValue="1"
            />
          </template>

          <!-- 日期选择 -->
          <template v-else-if="item.type === 'date'">
            <a-date-picker
              v-if="!props.readonly"
              style="width: 100%"
              :disabledDate="item.isAfterToday ? isAfterToday : null"
              v-model:value="props.modelValue[item.prop]"
              :placeholder="'请选择' + item.label"
              :valueFormat="item.dateFormat || 'YYYY-MM-DD'"
              :show-time="item.dateFormat?.includes('HH:mm')"
            />
            <span v-else>{{ props.modelValue[item.prop] }}</span>
          </template>

          <!-- 日期范围选择 -->
          <template v-else-if="item.type === 'date-range'">
            <a-range-picker
              v-if="!props.readonly"
              style="width: 100%"
              v-model:value="props.modelValue[item.prop]"
              :placeholder="['请选择开始时间', '请选择结束时间']"
              :valueFormat="item.dateFormat || 'YYYY-MM-DD'"
              :show-time="item.dateFormat?.includes('HH:mm')"
              :time-picker-props="{ defaultValue: ['00:00:00', '00:00:00'] }"
            />
            <span v-else>{{ props.modelValue[item.prop] }}</span>
          </template>

          <!-- 文件上传 -->
          <template v-else-if="item.type === 'upload'">
            <UploadFile
              :readonly="props.readonly"
              v-model="props.modelValue[item.prop]"
            />
          </template>

          <!-- 图片上传 -->
          <!-- 。。。 -->

          <!-- 常规表单项 -->
          <template v-else>
            <component
              v-if="!props.readonly"
              :mode="item.multiple ? 'multiple' : null"
              show-search
              :options="item.options"
              :filter-option="likeSearchFn"
              :is="FormItemMap[item.type]"
              v-model:value="props.modelValue[item.prop]"
              :placeholder="`请${placeholderText(item.type)}${item.label}`"
              :bind="{}"
              :style="{ width: item.width || '100%' }"
            >
              <!-- 选择项 -->
              <template v-if="OptionTypes.includes(item.type)">
                <component
                  :is="FormItemOptionMap[item.type]"
                  :value="option.value"
                  v-for="(option, i) in item.options"
                  :key="i"
                >
                  {{ option.label }}
                </component>
              </template>
            </component>

            <template v-else>
              <!-- 特殊内容回显 -->

              <!-- 在全局字典中包括： -->
              <template v-if="dictionaryKeys.includes(item.prop)">
                <span>{{
                  getValByDictionary(item.prop, props.modelValue)
                }}</span>
              </template>
              <!-- 常规文本回显 -->
              <span v-else>{{ props.modelValue[item.prop] }}</span>
            </template>
          </template>
        </a-form-item>
      </a-col>
      <slot name="footer"></slot>

      <a-col class="flex-1 flex-x-end">
        <a-form-item>
          <slot></slot>
        </a-form-item>
      </a-col>
    </a-row>
  </a-form>
</template>

<style lang="less" scoped></style>
